import logging
import traceback
from functools import lru_cache
from coin.base.datetime_util import to_timestamp_int
from coin.exchange.base.kr_rest.py_public_client import PyPublicClient
from coin.exchange.kr_rest.feed.feed_impl import generate_public_client
from coin.exchange.kr_rest.product.product_impl import generate_product_from_str2
from coin.proto.coin_request_pb2 import KlineRequestProto
from coin.support.market_quotes.logic.constants import kline_period_mapping
from coin.support.accounting.logic.query_util import multithread_request_executor
from xunkemgmt_client.client.util.query_util import query_exchange_apis
from xunkemgmt_client.support.accounting.database.db_output import DBOutputKline


def query_history_kline_list(request_list, start_time, end_time, no_throw=False):
  params_list = []

  for request in request_list:
    params_list.append([start_time, end_time, no_throw])

  def f(request, start_time, end_time, no_throw):
    try:
      result = query_history_kline(request, start_time, end_time)
    except Exception as e:
      if no_throw:
        logging.info('Skipping query kline:', request, type(e), e)
        logging.info(traceback.format_exc())
        result = None
      else:
        raise e
    return result

  response_list = multithread_request_executor(f, request_list, params_list)
  return response_list


@lru_cache(maxsize=16)
def _get_api_version(exchange_api_id):
  exchange_api_universe = query_exchange_apis(as_proto=True)
  for exchange_api in exchange_api_universe:
    if exchange_api.exchange_api_id == exchange_api_id:
      api_version = exchange_api.api_version if exchange_api.HasField('api_version') else None
      return api_version


def query_history_kline(request, start_time, end_time):
  market_type = request.market_type
  exchange = request.exchange
  kline_period = request.kline_period
  symbol_contract_type = request.symbol_contract_type
  api_version = _get_api_version(request.source_exchange_api_id)
  product = generate_product_from_str2(
      market_type, exchange, None, symbol_contract_type, end_time)
  client = generate_public_client(market_type, exchange, api_version)
  if isinstance(client, PyPublicClient):
    kline_request = KlineRequestProto(
        market_type=product.market_name,
        exchange=product.exchange_name,
        symbol=product.symbol,
        api_version=api_version,
        start_timestamp=to_timestamp_int(start_time),
        end_timestamp=to_timestamp_int(end_time),
        kline_period=kline_period)
    update = client.query_history_kline(kline_request)
    update.klines.sort(key=lambda x: x.kline_timestamp)
    obj = DBOutputKline(query_timestamp=None, klines=update)
  else:
    native_kline_period = kline_period_mapping(exchange, kline_period)
    update = client.query_history_kline(
        product, native_kline_period, start_time, end_time)
    update.msg.klines.sort(key=lambda x: x.kline_timestamp)
    obj = DBOutputKline(query_timestamp=update.req_timestamp, klines=update.msg)
  return obj
